#if __STDC_VERSION__ >= 199901L
#else
#define restrict
#endif

#ifdef _MSC_VER
#define inlint __forceinline
#endif

#ifdef __GNUC__
#define _PACKED __attribute__ ((packed))
#else
#define _PACKED
#endif

#define ARCH64 (__x86_64__ || __ppc64__ || _WIN64 || __LP64__)

#include <stdlib.h>
#include <string.h>

#include <gp_hash/gp_lz4.h>

#define HASH_LOG 12

#if defined(_MSC_VER)
#define BYTE unsigned __int8
#define U16 unsigned __int16
#define U32 unsigned __int32
#define S32 __int32
#define U64 unsigned __int64
#else
#include <stdint.h>
#define BYTE uint8_t
#define U16 uint16_t
#define U32 uint32_t
#define S32 int32_t
#define U64 uint64_t
#endif

#define MINMATCH 4
#define SKIPSTRENGTH 6
#define STACKLIMIT 13
#define HEAPMODE (HASH_LOG > STACKLIMIT)
#define COPYLENGTH 8
#define LASLITERALS 5
#define MFLIMIT (COPYLENGTH + MINMATCH)
#define MINLENGTH (MFLIMIT + 1)

#define MAXD_LOG 16
#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)

#define HASHTABLESIZE (1 << HASH_LOG)
#define HASH_MASK (HASHTABLESIZE - 1)

#define ML_BITS 4
#define ML_MASK ((1U << ML_BITS) - 1)
#define RUN_BITS (8 - ML_BITS)
#define RUN_MASK ((1U << RUN_BITS) - 1)

struct refTables {
  const BYTE* hashTable[HASHTABLESIZE];
};

typedef struct _U64_S {
  U64 v;
} _PACKED U64_S;

typedef struct _U32_S {
  U32 v;
} _PACKED U32_S;

typedef struct _U16_S {
  U16 v;
} _PACKED U16_S;

#define A64(x) (((U64_S *)(x))->v)
#define A32(x) (((U32_S *)(x))->v)
#define A16(x) (((U16_S *)(x))->v)

#if ARCH64
#define COPYSTEP 8
#define LZ4_COPYSTEP(s, d) A64(d) = A64(s); d+=8; s+=8;
#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d)
#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d)
#else
#define COPYSTEP 4
#define LZ4_COPYSTEP(s, d) A32(d) = A32(s); d+=4; s+=4;
#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d);
#endif

// TODO: LINE 156

struct refTables
{
  const BYTE* hashTable[HASHTABLESIZE];
};

typedef struct _U64_S
{
  U64 v;
} _PACKED U64_S;

typedef struct _U32_S
{
  U32 v;
} _PACKED U32_S;

typedef struct _U16_S
{
  U16 v;
} _PACKED U16_S;

#define A64(x) ( ( (U64_S*)(x) ) -> v )
#define A32(x) ( ( (U32_S*)(x) ) ->v )
#define A16(x) ( ( (U16_S*)(x) ) ->v )

#if ARCH64
#define COPYSTEP 8
#define LZ4_COPYSTEP(s, d) A64(d) = A64(s); d+=8; s+=8;
#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d)
#else // 32bit
#define COPYSTEP 4
#define LZ4_COPYSTEP(s, d) A32(d) = A32(s); d+=4; s+=4;
#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d);
#endif // architecture-specific macros

int LZ4_compressCtx(void** ctx, char* src,
                    char* dest, int isize)
{
#if HEAPMODE
  struct refTables* srt = (struct refTables*) (*ctx);
  const BYTE** HashTable;
#else
  const BYTE* HashTable[HASHTABLESIZE] = {0};
#endif

}